//
//  GenericTest.swift
//  swift-learningTests
//
//  Created by aron on 2018/5/17.
//  Copyright © 2018年 aron. All rights reserved.
//

import XCTest

class GenericTest: XCTestCase {
    
    override func setUp() {
        super.setUp()

        print("============")
    }
    
    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }
    
    func testExample() {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }
    
    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }
    
    func testGenericFunc() {
        var intA  = 100
        var intB = 200
        swap(&intA, &intB)
        print("a = \(intA)  b = \(intB)")
        
        var strA = "hello"
        var strB = "world"
        swap(&strA, &strB)
        print("a = \(strA)  b = \(strB)")

    }
    
    func testGenericStruct() {
        var stack = MyStack<Int>()
        var elem = stack.pop()
        if let e = elem {
            print("pop elem is \(e)")
        } else {
            print("no item")
        }
        
        stack.push(elem: 12)
        stack.push(elem: 15)
        
        elem = stack.pop()
        if let e = elem {
            print("pop elem is \(e)")
        } else {
            print("no item")
        }
    }
    
    func testWhere() {
        var tos = Stack<String>()
        tos.push("google")
        tos.push("runoob")
        tos.push("taobao")
        
        var aos = ["google", "runoob", "taobao"]
        
        if allItemsMatch(tos, aos) {
            print("匹配所有元素")
        } else {
            print("元素不匹配")
        }
    }
    
    // 泛型方法
    func swap<T>(_ a: inout T, _ b: inout T) {
        let tmp : T = a
        a = b
        b = tmp
    }
    
    
    // 泛型结构体
    struct MyStack<T> {
        var elements = [T]()
        mutating func push(elem : T) {
            elements.append(elem)
        }
        mutating func pop() -> T? {
            if elements.count <= 0 {
                return nil
            }
            let elem = elements.last
            elements.removeLast()
            return elem
        }
    }
    
}

// associatedtype实现的泛型
protocol Container {
    associatedtype ItemType
    // 添加一个新元素到容器里
    mutating func append(_ item: ItemType)
    // 获取容器中元素的数
    var count: Int { get }
    // 通过索引值类型为 Int 的下标检索到容器中的每一个元素
    subscript(i: Int) -> ItemType { get }
}

// // 遵循Container协议的泛型TOS类型
struct Stack<Element>: Container {
    // Stack<Element> 的原始实现部分
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    // Container 协议的实现部分
    mutating func append(_ item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}
// 扩展，将 Array 当作 Container 来使用
extension Array: Container {}

// FIXME: Where的用法
func allItemsMatch<C1: Container, C2: Container>
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
        
        // 检查两个容器含有相同数量的元素
        if someContainer.count != anotherContainer.count {
            return false
        }
        
        // 检查每一对元素是否相等
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }
        
        // 所有元素都匹配，返回 true
        return true
}

